package cz.muni.fi.pa165.creatures.services.impl;

import cz.muni.fi.pa165.creatures.dao.CreatureTypeDAO;
import cz.muni.fi.pa165.creatures.dao.WeaponDAO;
import cz.muni.fi.pa165.creatures.dto.CreatureTypeDTO;
import cz.muni.fi.pa165.creatures.dto.WeaponDTO;
import cz.muni.fi.pa165.creatures.dto.mapping.CreatureTypeMapping;
import cz.muni.fi.pa165.creatures.dto.mapping.WeaponMapping;
import cz.muni.fi.pa165.creatures.model.CreatureType;
import cz.muni.fi.pa165.creatures.model.CreatureTypeWeapon;
import cz.muni.fi.pa165.creatures.model.Weapon;
import cz.muni.fi.pa165.creatures.services.WeaponService;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * This class represents actual implementation of the
 * {@link cz.muni.fi.pa165.creatures.services.WeaponService}.
 *
 * @author xhajek11
 */
@Service
public final class WeaponServiceImpl implements WeaponService {

    private static final Logger logger =
            Logger.getLogger(WeaponServiceImpl.class.getName());

    @Autowired
    private WeaponDAO weaponDao;

    @Autowired
    private WeaponMapping weaponMapping;

    @Autowired
    private CreatureTypeMapping creatureTypeMapping;

    @Autowired
    private CreatureTypeDAO creatureTypeDAO;

    @Override
    @Transactional
    public Long create(final WeaponDTO weapon) {
        try {
            return weaponDao.create(weaponMapping.DTOtoEntity(weapon));
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional
    public void update(final WeaponDTO weapon) {
        try {
            weaponDao.update(weaponMapping.DTOtoEntity(weapon));
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional
    public void remove(final WeaponDTO weapon) {
        try {
            weaponDao.remove(weaponMapping.DTOtoEntity(weapon));
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public WeaponDTO getById(final Long id) {
        try {
            return weaponMapping.entityToDTO(weaponDao.get(id));
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Long getCount() {
        try {
            return weaponDao.getCount();
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public List<WeaponDTO> getAll() {
        List<WeaponDTO> weapons = new ArrayList<WeaponDTO>();
        try {
            for (Weapon w : weaponDao.getAll()) {
                weapons.add(weaponMapping.entityToDTO(w));
            }
            return weapons;
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public List<WeaponDTO> getAllNotAsignedByCreatureType(final CreatureTypeDTO creatureTypeDTO) {
        List<WeaponDTO> weapons = new ArrayList<WeaponDTO>();
        try {
            CreatureType crType = creatureTypeMapping.DTOtoEntity(creatureTypeDTO);
            CreatureType crTypeDB = creatureTypeDAO.get(crType.getId());
            if (crTypeDB == null) {
                return null;
            }

            for (Weapon weapon : weaponDao.getAll()) {
                boolean contained = false;

                for (CreatureTypeWeapon creatureTypeWeapon : weapon.getCreatureTypes()) {
                    if (creatureTypeWeapon.getCreatureType().equals(crTypeDB)) {
                        contained = true;
                    }

                    if (contained) {
                        break;
                    }
                }
                if (!contained) {
                    weapons.add(weaponMapping.entityToDTO(weapon));
                }
            }
            return weapons;
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional
    public void removeAll() {
        try {
            weaponDao.removeAll();
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }

    @Override
    @Transactional(readOnly = true)
    public WeaponDTO getByName(final String name) {
        try {
            return weaponMapping.entityToDTO(weaponDao.getByName(name));
        } catch (DataAccessException ex) {
            logger.log(Level.INFO, ex.getMessage());
            throw ex;
        }
    }
}